﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text;
using System.IO;

using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Zip;

namespace DashFire
{
  public class ZipHelper
  {
    public static bool ZipFile(string targetFilePath, string zipFilePath)
    {
      if (!File.Exists(targetFilePath)) {
        LogicForGfxThread.LogicLog("ZipFile failed. targetFilePath not exist: {0}", targetFilePath);
        return false;
      }
      bool needTempZipFile = false;
      bool issuccess = false;
      if (IsPathEqual(targetFilePath, zipFilePath)) {
        needTempZipFile = true;
        zipFilePath += ".zip";
      }
      GZipOutputStream zos = null;
      FileStream zipfs = null;
      try {
        if (File.Exists(zipFilePath)) {
          File.Delete(zipFilePath);
        }
        zipfs = File.Create(zipFilePath);
        if (zipfs == null) {
          throw new Exception("zipfs null");
        }
        zos = new GZipOutputStream(zipfs);
        if (zos == null) {
          throw new Exception("zos null");
        }
        zos.SetLevel(9);
        zos.EnableStoreModTime(false);

        byte[] buffer = File.ReadAllBytes(targetFilePath);
        if (buffer == null || buffer.Length <= 0) {
          throw new Exception("buffer null");
        }
        zos.Write(buffer, 0, buffer.Length);
        issuccess = true;
      } catch (Exception ex) {
        LogicForGfxThread.LogicLog("ZipFile failed. targetFilePath: {0} zipFilePath:{1} ex:{2}",
          targetFilePath, zipFilePath, ex);
        issuccess = false;
        return false;
      } finally {
        if (zos != null) {
          zos.Finish();
          zos.Close();
          zos = null;
        }
        if (zipfs != null) {
          zipfs.Close();
          zipfs = null;
        }
        if (issuccess && needTempZipFile) {
          File.Delete(targetFilePath);
          File.Move(zipFilePath, targetFilePath);
        }
      }
      return true;
    }
    public static bool UnzipFile(byte[] buffer, string unZipTarget)
    {
      if (buffer == null || buffer.Length <= 0) {
        LogicForGfxThread.LogicLog("UnzipFile failed. ");

        return false;
      }
      GZipInputStream zis = null;
      MemoryStream ms = null;
      FileStream streamWriter = null;
      try {
        string dirName = Path.GetDirectoryName(unZipTarget);
        if (!Directory.Exists(dirName)) {
          Directory.CreateDirectory(dirName);
        }
        streamWriter = File.Create(unZipTarget);
        if (streamWriter == null) {
          throw new Exception("streamWriter null");
        }
        ms = new MemoryStream(buffer, 0, buffer.Length);
        if (ms == null) {
          throw new Exception("ms null");
        }
        zis = new GZipInputStream(ms);
        if (zis == null) {
          throw new Exception("zis null");
        }
        byte[] data = new byte[2048];
        int size = 0;
        while (true) {
          size = zis.Read(data, 0, data.Length);
          if (size > 0) {
            streamWriter.Write(data, 0, size);
          } else {
            break;
          }
        }
      } catch (System.Exception ex) {
        LogicForGfxThread.LogicLog("UnzipFile failed. ex:{0}:{1}", ex.Message, ex.StackTrace);

        return false;
      } finally {
        if (streamWriter != null) {
          streamWriter.Flush();
          streamWriter.Close();
          streamWriter = null;
        }
        if (zis != null) {
          zis.Close();
          zis = null;
        }
        if (ms != null) {
          ms.Close();
          ms = null;
        }
      }
      return true;
    }
    public static bool UnzipFile(string zipFilePath, string unZipTarget)
    {
      if (!File.Exists(zipFilePath)) {
        LogicForGfxThread.LogicLog("UnzipFile failed. zipFilePath not exist: {0}", zipFilePath);
        return false;
      }
      try {
        byte[] buffer = File.ReadAllBytes(zipFilePath);
        return UnzipFile(buffer, unZipTarget);
      } catch (System.Exception ex) {
        LogicForGfxThread.LogicLog("UnzipFile failed. fileName:{0} target:{1} ex:{2}:{3}", zipFilePath, unZipTarget, ex.Message, ex.StackTrace);
        return false;
      }
    }
    private static bool IsPathEqual(string pathA, string pathB)
    {
      pathA = pathA.Replace("\\", "/");
      pathB = pathB.Replace("\\", "/");
      return pathA == pathB;
    }

    public static bool ZipDir(string targetDir, string zipFile, string[] exclude = null)
    {
      if (!Directory.Exists(targetDir)) {
        LogicForGfxThread.LogicLog("ZipDir failed. targetDir not exist: {0}", targetDir);
        return false;
      }
      ZipOutputStream zos = null;
      FileStream zipfs = null;
      FileStream fs = null;
      try {
        if (File.Exists(zipFile)) {
          File.Delete(zipFile);
        }
        zipfs = File.Create(zipFile);
        if (zipfs == null) {
          throw new Exception("zipfs null");
        }
        zos = new ZipOutputStream(zipfs);
        if (zos == null) {
          throw new Exception("zos null");
        }
        zos.SetLevel(9);
        List<string> fileList = GetFiles(targetDir, exclude);
        foreach (string fileItem in fileList) {
          fs = File.OpenRead(fileItem);
          if (fs == null) {
            throw new Exception("fs null");
          }
          byte[] buffer = new byte[fs.Length];
          fs.Read(buffer, 0, Convert.ToInt32(fs.Length));
          string file = fileItem.Replace(targetDir, "");
          if (!string.IsNullOrEmpty(file)) {
            ZipEntry entry = new ZipEntry(file);
            zos.PutNextEntry(entry);
            zos.Write(buffer, 0, Convert.ToInt32(fs.Length));
          }
          fs.Close();
          fs = null;
        }
      } catch (Exception ex) {
        LogicForGfxThread.LogicLog("ZipFile failed. targetDir: {0} zipFilePath:{1} ex:{2}",
          targetDir, zipFile, ex);
        return false;
      } finally {
        if (fs != null) {
          fs.Close();
          fs = null;
        }
        if (zos != null) {
          zos.Finish();
          zos.Close();
          zos = null;
        }
        if (zipfs != null) {
          zipfs.Close();
          zipfs = null;
        }
      }
      return true;
    }
    public static bool UnzipDir(string zipFilePath, string targetDir)
    {
      if (!File.Exists(zipFilePath)) {
        LogicForGfxThread.LogicLog("UnzipDir failed. zipFilePath not exist: {0}", zipFilePath);
        return false;
      }
      try {
        byte[] buffer = File.ReadAllBytes(zipFilePath);
        return UnzipDir(buffer, targetDir);
      } catch (System.Exception ex) {
        LogicForGfxThread.LogicLog("UnzipFile failed. fileName:{0} target:{1} ex:{2}:{3}", zipFilePath, targetDir, ex.Message, ex.StackTrace);
        return false;
      }
    }
    public static bool UnzipDir(byte[] buffer, string targetDir)
    {
      if (buffer == null || buffer.Length <= 0) {
        LogicForGfxThread.LogicLog("UnzipDir failed. ");
        return false;
      }
      string fileName = string.Empty;
      ZipInputStream zis = null;
      MemoryStream ms = null;
      FileStream streamWriter = null;
      try {
        ms = new MemoryStream(buffer);
        if (ms == null) {
          throw new Exception("fs null");
        }
        zis = new ZipInputStream(ms);
        if (ms == null) {
          throw new Exception("zis null");
        }
        ZipEntry theEntry;
        while ((theEntry = zis.GetNextEntry()) != null) {
          fileName = Path.Combine(targetDir, theEntry.Name);
          string directoryName = Path.GetDirectoryName(fileName);
          if (!Directory.Exists(directoryName)) {
            Directory.CreateDirectory(directoryName);
          }
          if (!string.IsNullOrEmpty(fileName)) {
            streamWriter = File.Create(fileName);
            if (streamWriter == null) {
              throw new Exception("streamWriter null");
            }
            byte[] data = new byte[theEntry.Size];
            int size = zis.Read(data, 0, data.Length);
            if (size > 0) {
              streamWriter.Write(data, 0, size);
              streamWriter.Flush();
            }
            streamWriter.Close();
            streamWriter = null;
          }
        }
      } catch (System.Exception ex) {
        LogicForGfxThread.LogicLog("UnzipFile failed. ex:{0}:{1}", ex.Message, ex.StackTrace);
        return false;
      } finally {
        if (streamWriter != null) {
          streamWriter.Close();
          streamWriter = null;
        }
        if (zis != null) {
          zis.Close();
          zis = null;
        }
        if (ms != null) {
          ms.Close();
          ms = null;
        }
      }
      return true;
    }
    public static List<string> GetFiles(string targetDir, string[] exclude = null)
    {
      List<string> list = new List<string>();
      string[] filenames = Directory.GetFiles(targetDir);
      bool isExclude = false;
      if (filenames != null && filenames.Length > 0) {
        foreach (string fileItem in filenames) {
          isExclude = false;
          if (exclude != null && exclude.Length > 0) {
            foreach (string excludeItem in exclude) {
              if (fileItem.EndsWith(excludeItem)) {
                isExclude = true;
                break;
              }
            }
          }
          if (!isExclude) {
            list.Add(fileItem);
          }
        }
      }
      string[] dirnames = Directory.GetDirectories(targetDir);
      if (dirnames != null && dirnames.Length > 0) {
        foreach (string dirItem in dirnames) {
          List<string> clist = GetFiles(dirItem, exclude);
          list.AddRange(clist);
        }
      }
      return list;
    }
  }
}
